/*
 * Copyright (C) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import Beacon from './Beacon';
import BeaconParser from './BeaconParser';
import { ble } from '@kit.ConnectivityKit';

class BeaconTransmitter {

  //  public static readonly SUPPORTED : number = 0
  //  public static readonly NOT_SUPPORTED_MIN_SDK : number = 1
  //  public static readonly NOT_SUPPORTED_BLE : number = 2
  //  public static readonly NOT_SUPPORTED_MULTIPLE_ADVERTISEMENTS : number = 3
  //  public static readonly NOT_SUPPORTED_CANNOT_GET_ADVERTISER : number = 4
  //  public static readonly NOT_SUPPORTED_CANNOT_GET_ADVERTISER_MULTIPLE_ADVERTISEMENTS : number = 5
  //  private static readonly TAG : string = "BeaconTransmitter"
  //  private BluetoothAdapter mBluetoothAdapter;
  //  private BluetoothLeAdvertiser mBluetoothLeAdvertiser;
  //  private mAdvertiseMode: number = AdvertiseSettings.ADVERTISE_MODE_LOW_POWER;
  //  private int mAdvertiseTxPowerLevel = AdvertiseSettings.ADVERTISE_TX_POWER_HIGH;
  private gattServer: ble.GattServer
  private mBeacon: Beacon
  private mBeaconParser: BeaconParser
  //  private AdvertiseCallback mAdvertisingClientCallback;
  private advResponse = {
    "serviceUuids": new Array(),
    "manufactureData": new Array(),
    "serviceData": new Array()
  }
  private mStarted: boolean
  //  private AdvertiseCallback mAdvertiseCallback;
  private mConnectable: boolean = false;

  // scan inteval
  private interval:number = 500;

  // power
  private powerLevel:number = 3;

  // default connect
  private connect:boolean = false;

  constructor(parser: BeaconParser) {
    this.mBeaconParser = parser;
    this.gattServer = ble.createGattServer()
  }

  /**
       * Tells if transmission has started
       * @return
       */
  public isStarted(): boolean{
    return this.mStarted;
  }

  /**
       * Sets the beacon whose fields will be transmitted
       * @param beacon
       */
  public setBeacon(beacon: Beacon): void {
    this.mBeacon = beacon;
  }

  /**
       * Sets the beaconParsser used for formatting the transmission
       * @param beaconParser
       */
  public setBeaconParser(beaconParser: BeaconParser): void{
    this.mBeaconParser = beaconParser;
  }

  /**
       * Whether the advertisement should indicate the device is connectable.
       * @param connectable
       */
  public setConnectable(connectable: boolean): void {
    this.mConnectable = connectable;
  }

  /**
       * @see #setConnectable(boolean)
       * @return connectable
       */
  public isConnectable(): boolean {
    return this.mConnectable;
  }

  /**
       * Starts this beacon advertising
       */
  public startAdvertising(beacon: Beacon): void {
    this.mBeacon = beacon;
    if (this.mBeacon == null) {
      throw new Error("Beacon cannot be null.  Set beacon before starting advertising");
    }
    let manufacturerCode = this.mBeacon.getManufacturer();
    let serviceUuid: number = -1;
    if (this.mBeaconParser.getServiceUuid() != null) {
      serviceUuid = this.mBeaconParser.getServiceUuid();
    }

    if (this.mBeaconParser == null) {
      throw new Error("You must supply a BeaconParser instance to BeaconTransmitter.");
    }

    let advertisingBytes: Array<number> = this.mBeaconParser.getBeaconAdvertisementData(this.mBeacon);

    let byteString: string = "";

    for (let i: number = 0; i < advertisingBytes.length; i++) {
      byteString += advertisingBytes[i].toFixed(2);
      byteString += " ";
    }
    console.log("Starting advertising with ID1: %s ID2: %s ID3: %s and data: %s of size "
    + "%s", this.mBeacon.getId1(),
        this.mBeacon.getIdentifiers().length > 1 ? this.mBeacon.getId2() : "",
        this.mBeacon.getIdentifiers().length > 2 ? this.mBeacon.getId3() : "", byteString,
      advertisingBytes.length);

    try {

      let serviceUuidsArry = new Array();
      let manufactureDataArry = new Array();
      let serviceDataArry = new Array();
      var ServiceData = {};
      var ManufactureData ={}
      if (serviceUuid > 0) {
        let serviceUuidBytes: number[] = [this.numberToByte(serviceUuid & 0xff),
        this.numberToByte((serviceUuid >> 8) & 0xff)]
        // parseUuidFrom(serviceUuidBytes);

        ServiceData = {
          "serviceUuid": serviceUuid,
          "serviceValue": advertisingBytes
        }

      } else {
        ManufactureData = {
          "manufactureId": manufacturerCode,
          "manufactureValue": advertisingBytes
        }
      }
      let advSettings = {
        "interval": this.interval,
        "txPower": this.powerLevel,
        "connectable": this.connect
      }
      manufactureDataArry.push(ManufactureData);
      serviceDataArry.push(ServiceData);
      serviceUuidsArry.push(serviceUuid)
      var advdata = {
        "serviceUuids": serviceUuidsArry,
        "manufactureData": manufactureDataArry,
        "serviceData": serviceDataArry
      };
      if (this.gattServer == null) {
        console.info("[bt_js] startAdvertising: please create gatt server instance first!");
      }

      ble.startAdvertising(advSettings, advdata);
      this.mStarted=true;
      console.log("Started advertisement with callback:");

    } catch (e) {
      console.log(e, "Cannot start advertising due to exception");
    }
  }

  public numberToByte(b: number): number{
    return Int8Array.from([(b | (0x01 << 8))])[0];
  }
  /**
       * Stops this beacon from advertising
       */
  public stopAdvertising(): void {
    if (!this.mStarted) {
      console.log("Skipping stop advertising -- not started");
      return;
    }
    console.log("Stopping advertising with object %s", JSON.stringify(this.gattServer));
    try {
      ble.stopAdvertising();
    } catch (e) {
      console.log("Bluetooth is turned off. Transmitter stop call failed.");
    }
    this.mStarted = false;
  }

  //   /**
  //     * Checks to see if this device supports beacon advertising
  //     * @return SUPPORTED if yes, otherwise:
  //     *          NOT_SUPPORTED_MIN_SDK
  //     *          NOT_SUPPORTED_BLE
  //     *          NOT_SUPPORTED_MULTIPLE_ADVERTISEMENTS
  //     *          NOT_SUPPORTED_CANNOT_GET_ADVERTISER
  //     */
  //    public static checkTransmissionSupported(context:Object):number {
  //        let stat:bluetooth.BluetoothState = bluetooth.getState()
  //        return stat;
  //    }
}

export default BeaconTransmitter